package cn.gok.springsecuritydemo05.filter;

import cn.gok.springsecuritydemo05.util.JWTUtil;
import cn.gok.springsecuritydemo05.util.ResultData;
import cn.hutool.json.JSONUtil;
import com.auth0.jwt.exceptions.JWTVerificationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;

/**
    自定义的JWT Token的校验过滤器
        每次请求，验证token的合法性，如果不合法，则让其重新登录
        如果合法，说明用户处于登录状态，并将token中的用户数据取出，存入到 SecurityContextHolder中，以便后续验证
 */
@Component
@Slf4j
public class JWTTokenAuthencationFilter extends OncePerRequestFilter {

    @Autowired
    JWTUtil jwtUtil;


    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        response.setContentType("application/json;charset=utf8");
        String jwtToken = request.getHeader("jwtToken");

        /*
            如果没有值，则直接将验证操作交给Spring Security 后续过滤器处理
                    当然结果肯定让其登录
         */
        if (jwtToken == null){
            filterChain.doFilter(request, response);
            return;
        }

        //验证token是否有效
        try {
            jwtUtil.verify(jwtToken);
        }catch (JWTVerificationException e) {
            log.error(e.getMessage(),e.getCause());
            response.getWriter().print(JSONUtil.toJsonStr(ResultData.fail("token有误，请登录后再做尝试")));
            return;
        }

        // 取出token的用户信息
        String[] roles = jwtUtil.getArrayValue(jwtToken, "roles", String.class);
        String username = jwtUtil.getValue(jwtToken, "username", String.class);

        //存入SecurityContextHolder中
        Collection<GrantedAuthority> authorities = new HashSet<>();
        for (String role : roles) {
            authorities.add(new SimpleGrantedAuthority( role));
        }
        User user = new User( username, "", true,true,true,true, authorities);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user,null,authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        //放行
        filterChain.doFilter(request,response);
    }
}
